﻿//  Copyright (c) 2009 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.Compilation;

namespace DNA.Mvc
{
    /// <summary>
    /// Exposes a node of a hierarchical data structure, including the node object and some properties that describe characteristics of the node.
    /// </summary>
    public class HierarchicalNode : INavigable
    {
        private IDictionary<string, object> attributes;
        private List<HierarchicalNode> _children;
        private HierarchicalNode _parentNode;
        private bool isReadOnly = false;
        private bool isParentset = false;
        private bool isChildrenset = false;
        private string _resourceKey;
        private string _title;
        private string _key;
        private string _url;
        private IHierarchicalNodeProvider _provider;
        private object _item;
        //private string _value;
        private string _target = "";
        private string _imageUrl = "";

        /// <summary>
        /// Gets/Sets the target window that opens the NavigateUrl of the Node.
        /// </summary>
        /// <remarks>
        ///  The value maybe set to window name,"_blank","_self","_top","_parents"
        /// </remarks>
        public string Target
        {
            get { return _target; }
            set { _target = value; }
        }

        /// <summary>
        /// Gets/Sets the image url of the node.
        /// </summary>
        public string ImageUrl
        {
            get { return _imageUrl; }
            set { _imageUrl = value; }
        }

        /// <summary>
        /// Gets/Sets navigate url of the node.
        /// </summary>
        public string NavigateUrl
        {
            get { return _url; }
            set { _url = value; }
        }

        /// <summary>
        /// Gets/Sets the key value of the node.
        /// </summary>
        public string Key
        {
            get { return _key; }
            set { _key = value; }
        }

        /// <summary>
        /// Gets the silbling nodes of this node.
        /// </summary>
        public List<HierarchicalNode> SiblingNodes
        {
            get
            {
                HierarchicalNode parentNode = this.ParentNode;
                if (parentNode != null)
                {
                    return parentNode.ChildNodes;
                }
                return null;
            }
        }

        /// <summary>
        /// Gets the next sibling node of this node.
        /// </summary>
        /// <value>If sibling node not found will be returns null.</value>
        public virtual HierarchicalNode NextSibling
        {
            get
            {
                var siblingNodes = this.SiblingNodes;
                if (siblingNodes != null)
                {
                    int index = siblingNodes.IndexOf(this);
                    if ((index >= 0) && (index < (siblingNodes.Count - 1)))
                    {
                        return (HierarchicalNode)siblingNodes[index + 1];
                    }
                }
                return null;
            }
        }
 
        /// <summary>
        /// Gets the previous sibling node of this node.
        /// </summary>
        /// <value>If previous node not found will be returns null.</value>
        public virtual HierarchicalNode PreviousSibling
        {
            get
            {
                var siblingNodes = this.SiblingNodes;
                if (siblingNodes != null)
                {
                    int index = siblingNodes.IndexOf(this);
                    if ((index > 0) && (index <= (siblingNodes.Count - 1)))
                    {
                        return (HierarchicalNode)siblingNodes[index - 1];
                    }
                }
                return null;
            }
        }

        /// <summary>
        /// Gets the node provider instance
        /// </summary>
        public IHierarchicalNodeProvider Provider 
        {
            get 
            {
                return this._provider; 
            } 
        }

        /// <summary>
        /// Gets/Sets identity wheather the node is readonly that all properties could not be modified.
        /// </summary>
        public bool IsReadOnly
        {
            get
            {
                return isReadOnly;
            }
            set
            {
                isReadOnly = value;
            }
        }

        /// <summary>
        /// Gets/Sets the node title
        /// </summary>
        //[System.ComponentModel.Localizable(true)]
        public string Title
        {
            get
            {
                if (this._provider!=null)
                {
                    if (this.Provider.EnableLocalization)
                    {
                        string implicitResourceString = this.GetImplicitResourceString("Title");
                        if (implicitResourceString != null)
                            return implicitResourceString;
                    }
                }
                if (this._title != null)
                    return this._title;
                return string.Empty;
            }
            set
            {
                if (this.isReadOnly)
                    throw new InvalidOperationException("NavigatableNode is readonly");
                this._title = value;
            }
        }

        /// <summary>
        /// Gets/Sets the parent node
        /// </summary>
        public virtual HierarchicalNode ParentNode
        {
            get
            {
                if (this.isParentset)
                    return this._parentNode;
                return this.Provider.GetParentNode(this);
            }
            set
            {
                if (this.isReadOnly)
                    throw new InvalidOperationException("The node is read only");
                _parentNode = value;
                isParentset = true;
            }
        }

        /// <summary>
        /// Gets/Sets the description of the node.
        /// </summary>
        public string Description { get; set; }

        public object Item { get{return _item;} set{_item=value; }}

        /// <summary>
        /// Identity the specified node is descendant  of this node.
        /// </summary>
        /// <param name="node">The node object.</param>
        /// <returns>Bool value</returns>
        public virtual bool IsDescendantOf(HierarchicalNode node)
        {
            for (HierarchicalNode node2 = this.ParentNode; node2 != null; node2 = node2.ParentNode)
            {
                if (node2.Equals(node))
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Initialize the HierarchialNode.
        /// </summary>
        public HierarchicalNode() { }

        /// <summary>
        /// Initialize the HierarchialNode by specified the provider.
        /// </summary>
        /// <param name="provider">The provider instance.</param>
        public HierarchicalNode(IHierarchicalNodeProvider provider)
        {
            this._provider = provider;
        }
         

        /// <summary>
        /// Gets the Children nodes 
        /// </summary>
        public virtual List<HierarchicalNode> ChildNodes
        {
            get
            {
                if (isChildrenset)
                    return this._children;
                var _nodes=Provider.GetChildNodes(this);
                if (_nodes != null)
                    return _nodes.ToList();
                return null;
            }
            set
            {
                if (this.isReadOnly)
                    throw new InvalidOperationException("The node is read only");
                _children = value;
                isChildrenset = true;
            }
        }

        /// <summary>
        /// The addition attributes of this node,it will be render as html attributes when using the HierarchicalNodeUIBuilder.
        /// </summary>
        public IDictionary<string, object> Attributes
        {
            get
            {
                if (attributes == null)
                    attributes = new Dictionary<string, object>();
                return attributes;
            }
            set 
            {
                attributes = value;
            }
        }

        public string ResourceKey { get { return _resourceKey; } set { _resourceKey = value; } }

        /// <summary>
        /// Gets the roles who can access this node
        /// </summary>
        public string[] Roles
        {
            get
            {
                return Provider.GetNodeRoles(this);
            }
        }

        /// <summary>
        /// Gets wheather current user could access this node by specified the httpcontext instance.
        /// </summary>
        /// <param name="context">The HttpContext object.</param>
        /// <returns>The bool value.</returns>
        public virtual bool IsAccessibleToUser(HttpContext context)
        {
            return this.Provider.IsAccessibleToUser(context, this);
        }

        /// <summary>
        /// Gets wheather current user could access this node.
        /// </summary>
        /// <returns>The bool value.</returns>
        public bool IsAccessibleToUser()
        {
            return IsAccessibleToUser(HttpContext.Current);
        }

        /// <summary>
        /// Get the resource string form the resource files
        /// </summary>
        /// <param name="attributeName">the resource name</param>
        /// <returns></returns>
        protected string GetImplicitResourceString(string attributeName)
        {
            if (attributeName == null)
            {
                throw new ArgumentNullException("attributeName");
            }
            string globalResourceObject = null;
            if (!string.IsNullOrEmpty(this._resourceKey))
            {
                try
                {
                    globalResourceObject = HttpContext.GetGlobalResourceObject(this.Provider.ResourceKey, this.ResourceKey + "." + attributeName) as string;
                }
                catch
                {
                }
            }
            return globalResourceObject;
        }

        /// <summary>
        /// Gets the root node
        /// </summary>
        public virtual HierarchicalNode RootNode 
        { 
            get
            {
                if (_provider!=null)
                    return Provider.RootNode;
                return null;
               } 
        }

        /// <summary>
        /// Identity this node has any childnodes
        /// </summary>
        public bool HasChildNodes
        {
            get
            {
                return ((ChildNodes != null) && (ChildNodes.Count > 0));
            }
        }

        public virtual string ToJsonString()
        {
            return "";
        }

        /// <summary>
        /// Get all childrens in a collection
        /// </summary>
        /// <returns></returns>
        public List<HierarchicalNode> GetAllChildren()
        {
            var children = new List<HierarchicalNode>();
            this.GetAllNodesRecursive(children);
            return children;
        }

        public void Remove()
        {
            Provider.RemoveNode(this);
        }

        /// <summary>
        /// Add the children node to this node by specified the HierarchicalNode instance.
        /// </summary>
        /// <param name="node">The node object to be added.</param>
        public void AddChildren(HierarchicalNode node)
        {
            Provider.AddChildren(this, node);
        }

        public override bool Equals(object obj)
        {
            HierarchicalNode node = obj as HierarchicalNode;
            return (((node != null) && (this._key == node.Key)) && string.Equals(this._url, node._url, StringComparison.OrdinalIgnoreCase));
        }

        private void GetAllNodesRecursive(List<HierarchicalNode> nodes)
        {
            var childrenNodes = this.ChildNodes;
            if ((childrenNodes != null) && (childrenNodes.Count > 0))
            {
                nodes.AddRange(childrenNodes);
                foreach (var n in childrenNodes)
                    n.GetAllNodesRecursive(nodes);
            }
        }

        #region INavigate members

        string INavigable.Description
        {
            get { return this.Description; }
        }

        string INavigable.Title
        {
            get { return this.Title; }
        }

        string INavigable.NavigateUrl
        {
            get { return this.NavigateUrl; }
        }

        string INavigable.ImageUrl
        {
            get { return this.ImageUrl; }
        }
        
        string INavigable.Target
        {
            get { return this.Target; }
        }

        object INavigable.Value
        {
            get {
                return this.Item;
            }
        }

        #endregion
    }
   
}
